package com.xinzhidi.web.netty.service;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinzhidi.common.constant.AgreementConstants;
import com.xinzhidi.common.core.domain.model.LoginUser;
import com.xinzhidi.common.core.page.TableDataInfo;
import com.xinzhidi.common.exception.ServiceException;
import com.xinzhidi.common.utils.DateUtils;
import com.xinzhidi.common.utils.SecurityUtils;
import com.xinzhidi.common.utils.StringUtils;
import com.xinzhidi.common.utils.bean.BeanUtils;
import com.xinzhidi.common.utils.file.FileTypeUtils;
import com.xinzhidi.web.build.domain.BuildUnit;
import com.xinzhidi.web.build.service.IBuildUnitService;
import com.xinzhidi.web.equipment.domain.vo.EquipmentInfoVo;
import com.xinzhidi.web.equipment.service.EquipmentService;
import com.xinzhidi.web.netty.entity.*;
import com.xinzhidi.web.netty.entity.dto.AgreementUnitValveAddDto;
import com.xinzhidi.web.netty.entity.dto.AgreementUnitValveListDto;
import com.xinzhidi.web.netty.entity.dto.AgreementUnitValveUpdDto;
import com.xinzhidi.web.netty.entity.dto.WriteSystemInformationDto;
import com.xinzhidi.web.netty.entity.po.AgreementCommandPo;
import com.xinzhidi.web.netty.entity.vo.AgreementUnitValveInfoVo;
import com.xinzhidi.web.netty.entity.vo.AgreementUnitValveListVo;
import com.xinzhidi.web.netty.mapper.AgreementUnitValveMapper;
import com.xinzhidi.web.netty.utils.FormatData;
import com.xinzhidi.web.netty.utils.HexadecimalUtil;
import com.xinzhidi.web.netty.utils.NettyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 单元阀门协议-（实时数据）Service业务层处理
 *
 * @author cx
 * @date 2023-06-17
 */
@Service
public class AgreementUnitValveService extends ServiceImpl<AgreementUnitValveMapper, AgreementUnitValve> {
    @Autowired
    private AgreementUnitValveMapper agreementUnitValveMapper;

    @Autowired
    private AgreementCommandService commandService;

    @Autowired
    private AgreementCommandFieldService commandFieldService;

    @Autowired
    private AgreementUnitValveHistoryService unitValveHistoryService;

    @Autowired
    private DeviceInstructionService deviceInstructionService;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private AgreementUnitValveService UnitValveService;

    @Autowired
    private IBuildUnitService unitService;

    @Autowired
    private AgreementHouseholdValveService householdValveService;

    /**
     * 查询单元阀门协议-（实时数据）
     *
     * @param id 单元阀门协议-（实时数据）主键
     * @return 单元阀门协议-（实时数据）
     */
    public AgreementUnitValveInfoVo selectAgreementUnitValveById(Long id) {
        AgreementUnitValve agreementUnitValve = agreementUnitValveMapper.selectById(id);
        AgreementUnitValveInfoVo infoVo = new AgreementUnitValveInfoVo();
        BeanUtils.copyProperties(agreementUnitValve, infoVo);
        return infoVo;
    }

    /**
     * 查询单元阀门协议-（实时数据）列表
     *
     * @param dto 查询单元阀门协议-（实时数据）dto
     * @return 单元阀门协议-（实时数据）
     */
    public TableDataInfo<AgreementUnitValveListVo> selectAgreementUnitValveList(AgreementUnitValveListDto dto) {
        LambdaQueryWrapper<AgreementUnitValve> wrapper = Wrappers.lambdaQuery();
        wrapper.orderByDesc(AgreementUnitValve::getId);
        return TableDataInfo.getDataTable(agreementUnitValveMapper.selectList(wrapper), (domain -> {
            AgreementUnitValveListVo vo = new AgreementUnitValveListVo();
            BeanUtils.copyProperties(domain, vo);
            return vo;
        }));
    }

    /**
     * 新增单元阀门协议-（实时数据）
     *
     * @param dto 新增单元阀门协议-（实时数据）dto
     * @return 结果
     */
    public int insertAgreementUnitValve(AgreementUnitValveAddDto dto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();

        AgreementUnitValve agreementUnitValve = new AgreementUnitValve();
        BeanUtils.copyProperties(dto, agreementUnitValve);
        agreementUnitValve.setCreateBy(loginUser.getUserId().toString());
        agreementUnitValve.setCreateTime(DateUtils.getNowDate());
        return agreementUnitValveMapper.insert(agreementUnitValve);
    }

    /**
     * 修改单元阀门协议-（实时数据）
     *
     * @param dto 修改单元阀门协议-（实时数据）dto
     * @return 结果
     */
    public int updateAgreementUnitValve(AgreementUnitValveUpdDto dto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();

        AgreementUnitValve agreementUnitValve = new AgreementUnitValve();
        BeanUtils.copyProperties(dto, agreementUnitValve);
        agreementUnitValve.setUpdateBy(loginUser.getUserId().toString());
        agreementUnitValve.setUpdateTime(DateUtils.getNowDate());
        return agreementUnitValveMapper.updateById(agreementUnitValve);
    }

    /**
     * 批量删除单元阀门协议-（实时数据）
     *
     * @param ids 需要删除的单元阀门协议-（实时数据）主键
     * @return 结果
     */
    public int deleteAgreementUnitValveByIds(Long[] ids) {
        return agreementUnitValveMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除单元阀门协议-（实时数据）信息
     *
     * @param id 单元阀门协议-（实时数据）主键
     * @return 结果
     */
    public int deleteAgreementUnitValveById(Long id) {
        return agreementUnitValveMapper.deleteById(id);
    }

    public AgreementUnitValve getAgreementUnitValve(AgreementUnitValveListDto dto) {
        AgreementUnitValve unitValve = agreementUnitValveMapper.selectOne(buildGenTableQueryWrapper(dto));
        return unitValve;
    }

    /**
     * 单元阀门协议解析
     *
     * @param deviceInstruction 下发指令
     * @param message           消息
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> receiveUnitValve(String message, DeviceInstruction deviceInstruction) {
//        LambdaQueryWrapper<AgreementUnitValveHistory> wrapper = new LambdaQueryWrapper<>();
//        wrapper.orderByDesc(AgreementUnitValveHistory::getCreateTime).last(" limit 1");

        LambdaQueryWrapper<AgreementCommand> commandWrapper = new LambdaQueryWrapper<>();
        commandWrapper.eq(AgreementCommand::getType, AgreementConstants.InstructionType.RECEIVE)
                .eq(AgreementCommand::getProtocolType, deviceInstruction.getProtocolType())
                .eq(AgreementCommand::getInstructType, deviceInstruction.getInstructType());
        AgreementCommand command = commandService.getOne(commandWrapper);

        LambdaQueryWrapper<AgreementCommandField> commandFieldLambdaQueryWrapper = new LambdaQueryWrapper<>();
        commandFieldLambdaQueryWrapper.eq(AgreementCommandField::getCommandId, command.getId())
                .orderByAsc(AgreementCommandField::getSort);
        List<AgreementCommandField> commandFieldList = commandFieldService.list(commandFieldLambdaQueryWrapper);
        Map<String, Object> map = new HashMap<>();
        for (AgreementCommandField commandField : commandFieldList) {
            Integer startNum = commandField.getStartNum();
            Integer endNum = commandField.getEndNum();
            String value = NettyUtils.getByteStr(startNum, endNum, message, commandField);
            FileTypeUtils.setValueByType(commandField.getFieldEnglish(), commandField.getFieldType(), map, value);
        }
        //保存单元阀门协议-实时数据表（agreement_unit_valve）、单元阀门协议-历史数据表（agreement_unit_valve_history）
        saveAgreementUnitValve(message, map, command, deviceInstruction);
        //修改单元阀门实时数据
        //如果是业务标识为1的数据，表示没有平台上的业务，不做任何操作
        if (!deviceInstruction.getBusinessFlag().equals("1")) {
            //修改住户阀门实时数据
            Integer valveOpen = Double.valueOf(map.get("readOpenValue").toString()).intValue();
            UpdateWrapper<BuildUnit> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("valve_open", valveOpen)
                    .eq("id", deviceInstruction.getUnitId());
            unitService.update(updateWrapper);
        }
        return map;
    }

    /**
     * 保存单元阀门协议-实时数据表（agreement_unit_valve）、单元阀门协议-历史数据表（agreement_unit_valve_history）
     */
    private Map<String, Object> saveAgreementUnitValve(
            String message,
            Map<String, Object> map,
            AgreementCommand command,
            DeviceInstruction deviceInstruction) {
        AgreementUnitValve unitValve;
        //判断户用阀门实时数据是否已存在，存在则更新，不存在则新增
        AgreementUnitValveListDto dto = new AgreementUnitValveListDto();
        dto.setDtuId(deviceInstruction.getDtuId());
        dto.setAddress(deviceInstruction.getAddress());
        dto.setInstructType(command.getInstructType());
        unitValve = this.getAgreementUnitValve(dto);
        String dataFieldSerialNumber = this.getDataFieldSerialNumber(dto);
        if (unitValve != null) {
            unitValve.setInstructionSet(message);
            unitValve.setJsonData(JSON.toJSONString(map));
            unitValve.setUpdateTime(DateUtils.getNowDate());
        } else {
            unitValve = new AgreementUnitValve();
            unitValve.setDeviceInstructionId(deviceInstruction.getId());
            unitValve.setDtuId(deviceInstruction.getDtuId());
            unitValve.setProtocolName(command.getProtocolName());
            unitValve.setInstructType(command.getInstructType());
            unitValve.setInstructName(command.getInstructName());
            unitValve.setPlotId(deviceInstruction.getPlotId());
            unitValve.setBuildId(deviceInstruction.getBuildId());
            unitValve.setUnitId(deviceInstruction.getUnitId());
            unitValve.setHouseholdId(deviceInstruction.getHouseholdId());
            unitValve.setDeviceType(command.getDeviceType());
            unitValve.setAddress(deviceInstruction.getAddress());
            unitValve.setInstructionSet(message);
            unitValve.setJsonData(JSON.toJSONString(map));
        }
        unitValve.setDataFieldSerialNumber(dataFieldSerialNumber);
        if (this.saveOrUpdate(unitValve)) {
            LambdaQueryWrapper<AgreementCommand> commandWrapper = new LambdaQueryWrapper<>();
            commandWrapper.eq(AgreementCommand::getType, AgreementConstants.InstructionType.RECEIVE)
                    .eq(AgreementCommand::getProtocolType, deviceInstruction.getProtocolType())
                    .eq(AgreementCommand::getInstructType, deviceInstruction.getInstructType());
            command = commandService.getOne(commandWrapper);
            //保存单元阀门协议-历史数据表（agreement_unit_valve_history）
            AgreementUnitValveHistory unitValveHistory = new AgreementUnitValveHistory();
            unitValveHistory.setDeviceInstructionId(deviceInstruction.getId());
            unitValveHistory.setDtuId(deviceInstruction.getDtuId());
            unitValveHistory.setProtocolName(command.getProtocolName());
            unitValveHistory.setInstructType(command.getInstructType());
            unitValveHistory.setInstructName(command.getInstructName());
            unitValveHistory.setPlotId(deviceInstruction.getPlotId());
            unitValveHistory.setBuildId(deviceInstruction.getBuildId());
            unitValveHistory.setUnitId(deviceInstruction.getUnitId());
            unitValveHistory.setHouseholdId(deviceInstruction.getHouseholdId());
            unitValveHistory.setDeviceType(command.getDeviceType());
            unitValveHistory.setAddress(deviceInstruction.getAddress());
            unitValveHistory.setInstructionSet(message);
            unitValveHistory.setPrefix(command.getPrefix());
            unitValveHistory.setDeviceType(command.getDeviceType());
            unitValveHistory.setControlCode(command.getControlCode());
            unitValveHistory.setLengthField(command.getLengthField());
            unitValveHistory.setStartChar(command.getStartChar());
            unitValveHistory.setJsonData(JSON.toJSONString(map));
            unitValveHistory.setDataFieldMark(command.getDataMark());
            unitValveHistory.setEndMark(command.getEndMark());
            unitValveHistory.setDataFieldSerialNumber(dataFieldSerialNumber);
            unitValveHistoryService.save(unitValveHistory);
        }
        deviceInstruction.setStatus(AgreementConstants.InstructSendingState.RETURN_TO_NORMAL);
        deviceInstructionService.updateById(deviceInstruction);
        return map;
    }

    private LambdaQueryWrapper<AgreementUnitValve> buildGenTableQueryWrapper(AgreementUnitValveListDto dto) {
        LambdaQueryWrapper<AgreementUnitValve> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotBlank(dto.getProtocolName()), AgreementUnitValve::getProtocolName, dto.getProtocolName())
                .like(StringUtils.isNotBlank(dto.getInstructName()), AgreementUnitValve::getInstructName, dto.getInstructName())
                .eq(StringUtils.isNotBlank(dto.getInstructType()), AgreementUnitValve::getInstructType, dto.getInstructType())
                .eq(StringUtils.isNotNull(dto.getDtuId()), AgreementUnitValve::getDtuId, dto.getDtuId())
                .eq(StringUtils.isNotBlank(dto.getAddress()), AgreementUnitValve::getAddress, dto.getAddress());
        return wrapper;
    }

    /**
     * 获取序列号---dataFieldSerialNumber
     */
    public String getDataFieldSerialNumber(AgreementUnitValveListDto dto) {
        Integer number = 0;
        AgreementUnitValve unitValve = this.getAgreementUnitValve(dto);
        if (unitValve == null) {
            return number.toString();
        }

        number = Integer.valueOf(unitValve.getDataFieldSerialNumber());
        if (number == 256) {
            number = 0;
        } else {
            number++;
        }

        return String.valueOf(number);
    }

    /**
     * 户用阀门-【读阀门地址】指令下发
     */
    public boolean readValveAddress(Long dtuId) {
        return householdValveService.readAddress(AgreementConstants.AgreementType.UNIT_VALVE, "7", dtuId);
    }

    /**
     * 户用阀门-【写阀门地址】指令下发
     */
    public boolean writeValveAddress(Long dtuId, String oldAddress, String newAddress) {
        return householdValveService.saveAddressDeviceInstruction(AgreementConstants.AgreementType.UNIT_VALVE, "8", dtuId, oldAddress, newAddress);
    }

    /**
     * 单元阀门-【读 系 统 信 息】指令下发
     */
    public boolean readSystemInformation(Long dtuId, String address) {
        return this.saveDeviceInstruction(dtuId, address, "1", "");
    }


    /**
     * 组装指令表数据
     */
    public boolean saveDeviceInstruction(Long dtuId, String address, String instructType, String value) {

        //获取设备信息
        EquipmentInfoVo infoVo = equipmentService.getEquipmentInfoVo(dtuId, address);

        AgreementCommandPo agreementCommandPo = new AgreementCommandPo();
        agreementCommandPo.setProtocolType(AgreementConstants.AgreementType.UNIT_VALVE);
        agreementCommandPo.setType(AgreementConstants.InstructionType.SEND);
        agreementCommandPo.setInstructType(instructType);
        AgreementCommand command = commandService.getProtocolInstruction(agreementCommandPo);
        if (command == null) {
            throw new ServiceException("指令不存在！");
        }

        //获取序列号
        AgreementUnitValveListDto dto = new AgreementUnitValveListDto();
        dto.setDtuId(dtuId);
        dto.setAddress(address);
        dto.setInstructType(instructType);
        //获取序列号
        String ser = "";
        ser = FormatData.tenToHexadecimal(Integer.valueOf(UnitValveService.getDataFieldSerialNumber(dto)), 1);
        String message = commandService.assemblyUnitValveInstruction(command, address, ser, value);

        DeviceInstruction instruction = new DeviceInstruction();
        //组装DeviceInstruction数据
        instruction.setDtuId(dtuId);
        instruction.setBusinessType(AgreementConstants.InstructBusinessType.OTHER);
        instruction.setProtocolType(AgreementConstants.AgreementType.UNIT_VALVE);
        instruction.setProtocolName(AgreementConstants.AgreementTypeName.UNIT_VALVE);
        instruction.setInstructType(command.getInstructType());
        instruction.setInstructName(command.getInstructName());
        instruction.setPlotId(infoVo.getLotId());
        instruction.setBuildId(infoVo.getBuildId());
        instruction.setUnitId(infoVo.getUnitId());
        instruction.setHouseholdId(infoVo.getHouseholdId());
        instruction.setAddress(infoVo.getAddress());
        instruction.setInstructionSet(message);
        return deviceInstructionService.save(instruction);
    }

    /**
     * 单元阀门-【写 系 统 信 息】指令下发
     */
    public boolean writeSystemInformation(WriteSystemInformationDto dto) {
        String workModel = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getWorkModel(), 2));
        String singleStepOpen = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getSingleStepOpen(), 2));
        String intervalTime = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getIntervalTime(), 2));
        String openValveUpper = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getOpenValveUpper(), 2));
        String openValveLower = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getOpenValveLower(), 2));
        String returnWaterLimit = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getReturnWaterLimit(), 2));
        String temperatureSetValue = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getTemperatureSetValue(), 2));
        String temperatureDeviation = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getTemperatureDeviation(), 2));
        String temperatureDeadValue = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(dto.getTemperatureDeadValue(), 2));

        String value = workModel + singleStepOpen + intervalTime + openValveUpper + openValveLower + returnWaterLimit + temperatureSetValue + temperatureDeviation + temperatureDeadValue;

        return this.saveDeviceInstruction(dto.getDtuId(), dto.getAddress(), "2", value);
    }

    /**
     * 单元阀门-【阀门控制-设置阀门开度】指令下发
     */
    public boolean setValveOpen(Long dtuId, String address, Integer valveOpen) {
        String value = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(valveOpen * 10, 2));
        return this.saveDeviceInstruction(dtuId, address, "3", value);
    }

    /**
     * 单元阀门-【阀门控制-顺时针旋转】指令下发
     */
    public boolean clockwiseRotation(Long dtuId, String address, Integer degrees) {
        String value = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(degrees, 2));
        return this.saveDeviceInstruction(dtuId, address, "4", value);
    }

    /**
     * 单元阀门-【阀门控制-逆时针旋转】指令下发
     */
    public boolean CounterclockwiseRotation(Long dtuId, String address, Integer degrees) {
        String value = HexadecimalUtil.hexConvertToHighLow(FormatData.tenToHexadecimal(degrees, 2));
        return this.saveDeviceInstruction(dtuId, address, "5", value);
    }

    /**
     * 单元阀门-【停止阀门】指令下发
     */
    public boolean stopValve(Long dtuId, String address) {
        return this.saveDeviceInstruction(dtuId, address, "6", "");
    }


}
